package com.hexinfo.dmpro.sparing.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.file.FileAppender;
import cn.hutool.core.util.StrUtil;
import com.hexinfo.dmpro.sparing.dto.StateDataDTO;
import com.hexinfo.dmpro.sparing.service.FutureService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

@Service
@Slf4j
public class FutureServiceImpl implements FutureService {

    @Value("${threadMonitoring}")
    private long threadMonitoring;

    /**
     * 判断所有获取是否全部完成
     */
    @Override
    public StateDataDTO futureStatusMap(Map<String,Future<Boolean>> futureMap, FileAppender heatLog,String message){
        StateDataDTO stateDataDTO = new StateDataDTO();
        stateDataDTO.setState(true);
        List<String> messageList = new ArrayList<>();
        //会等待所有线程都执行结束，拿到结果
        for (String key : futureMap.keySet()) {
            try {
                Future<Boolean> booleanFuture = futureMap.get(key);
                Object obj = booleanFuture.get(threadMonitoring, TimeUnit.SECONDS); // 等待3小时
                Boolean status = booleanFuture.get();
                if (!status){
                    stateDataDTO.setState(false);
                    messageList.add(StrUtil.format("【异常】【线程异常】【{}】【{}】",message,key));
                }
                // 处理任务结果
            } catch (InterruptedException e) {
                // 当前线程被中断
                stateDataDTO.setState(false);
                log.error("线程中断", e);
                messageList.add(StrUtil.format("【异常】【线程中断】【{}】【{}】",message,key));
                heatLog.append(logTime(StrUtil.format("【异常】【线程中断】【{}】【{}】",message,key)));
//                // 处理中断异常，例如清除中断状态或重新抛出
//                Thread.currentThread().interrupt();
            } catch (ExecutionException e) {
                // 处理任务执行异常
                stateDataDTO.setState(false);
                log.error("线程执行异常", e.getCause());// 获取实际的异常原因
                messageList.add(StrUtil.format("【异常】【线程执行异常】【{}】【{}】",message,key));
                heatLog.append(logTime(StrUtil.format("【异常】【线程执行异常】【{}】【{}】",message,key)));
            } catch (TimeoutException e) {
                // 等待超时
                stateDataDTO.setState(false);
                log.error("线程超时", e);
                futureMap.get(key).cancel(true); // 取消任务执行
                messageList.add(StrUtil.format("【异常】【线程超时】【{}】【{}】",message,key));
                heatLog.append(logTime(StrUtil.format("【异常】【线程超时】【{}】【{}】",message,key)));
            }
        }
        stateDataDTO.setDataList(messageList);
        return stateDataDTO;
    }

    /**
     * 判断所有获取是否全部完成
     */
    @Override
    public StateDataDTO futureStatusList(List<Future<Boolean>> futures, FileAppender heatLog,String message){
        StateDataDTO stateDataDTO = new StateDataDTO();
        stateDataDTO.setState(true);
        List<String> messageList = new ArrayList<>();
        //会等待所有线程都执行结束，拿到结果
        for (Future<Boolean> future : futures) {
            try {
                Object obj = future.get(threadMonitoring, TimeUnit.SECONDS); // 等待3小时
                Boolean status = future.get();
                if (!status){
                    stateDataDTO.setState(false);
                }
                // 处理任务结果
            } catch (InterruptedException e) {
                // 当前线程被中断
                stateDataDTO.setState(false);
                log.error("线程中断", e);
                messageList.add(StrUtil.format("【异常】【线程中断】【{}】",message));
                heatLog.append(logTime(StrUtil.format("【异常】【线程中断】【{}】",message)));
            } catch (ExecutionException e) {
                // 处理任务执行异常
                stateDataDTO.setState(false);
                log.error("线程执行异常", e.getCause());// 获取实际的异常原因
                messageList.add(StrUtil.format("【异常】【线程执行异常】【{}】",message));
                heatLog.append(logTime(StrUtil.format("【异常】【线程执行异常】【{}】",message)));
            } catch (TimeoutException e) {
                // 等待超时
                stateDataDTO.setState(false);
                log.error("线程超时", e);
                future.cancel(true); // 取消任务执行
                messageList.add(StrUtil.format("【异常】【线程超时】【{}】",message));
                heatLog.append(logTime(StrUtil.format("【异常】【线程超时】【{}】",message)));
            }
        }
        stateDataDTO.setDataList(messageList);
        return stateDataDTO;
    }

    /**
     * 日志加日期时间
     * @param str
     * @return
     */
    private String logTime(String str) {
        return "["+ DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:mm:ss")+"]" +str;
    }
    @Override
    public String futureResult(List<Future<Map<String, Object>>> futures) {
        Map<String,Integer> errMap = new HashMap<>();
        errMap.put("当前线程被中断",0);
        errMap.put("处理任务执行异常",0);
        errMap.put("等待超时",0);
        String err = "";
        //会等待所有线程都执行结束，拿到结果
        for (Future future : futures) {
            try {
                Object obj = future.get(Long.valueOf(threadMonitoring), TimeUnit.SECONDS); // 等待3小时
                // 处理任务结果
            } catch (InterruptedException e) {
                // 当前线程被中断
                log.error("当前线程被中断", e);
                errMap.put("当前线程被中断",errMap.get("当前线程被中断")+1);
            } catch (ExecutionException e) {
                // 处理任务执行异常
                log.error("处理任务执行异常", e.getCause());// 获取实际的异常原因
                errMap.put("处理任务执行异常",errMap.get("处理任务执行异常")+1);
            } catch (TimeoutException e) {
                // 等待超时
                log.error("等待超时", e);
                try {
                    future.cancel(true); // 取消任务执行
                } catch (Exception ex) {
                    throw new RuntimeException(ex);
                }
                errMap.put("等待超时",errMap.get("等待超时")+1);
            }
        }
        //分析错误数量
        for (String e :errMap.keySet()){
            if(errMap.get(e)>0){
                err += e + "【"+ errMap.get(e) + "】/";
            }
        }
        return err;
    }
}